﻿/* 项目名称： Messenger.cs
 * 命名空间： Vampirewal.Core.SimpleMVVM
 * 类 名 称: Messenger
 * 作   者 : 杨程
 * 概   述 :
 * 创建时间 : 2021/2/20 18:31:26
 * 更新时间 : 2021/2/20 18:31:26
 * CLR版本 : 4.0.30319.42000
 * ******************************************************
 * Copyright@Administrator 2021 .All rights reserved.
 * ******************************************************
 */

namespace Vampirewal.Core.Components;

/// <summary>
/// 消息通知类
/// <para >此处代码引用自 若汝棋茗</para>
/// <para >CSDN博客：https://blog.csdn.net/qq_40374647/article/details/127651804?spm=1001.2014.3001.5501</para>
/// <para >哔哩哔哩视频：https://space.bilibili.com/94253567</para>
/// <para >Gitee源代码仓库：https://gitee.com/RRQM_Home</para>
/// <para >Github源代码仓库：https://github.com/RRQM</para>
/// <para >API首页：https://www.yuque.com/rrqm/touchsocket/index</para>
/// <para >交流QQ群：234762506</para>
/// </summary>
public sealed class VampirewalMessenger : BaseSingleton<VampirewalMessenger>
{
    /// <summary>
    /// 注册消息
    /// </summary>
    public void RegistAll()
    {
        //var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IMessageManager)))).ToArray();
        var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(t => t.GetInterfaces().Contains(typeof(IVampirewalMessageManager))).ToArray();
        foreach (var v in types)
        {
            object obj = Activator.CreateInstance(v);
            MethodInfo[] methods = obj.GetType().GetMethods().Where(w => w.GetCustomAttribute<RegistMethodAttribute>() != null).ToArray();
            foreach (var item in methods)
            {
                RegistMethodAttribute attribute = item.GetCustomAttribute<RegistMethodAttribute>();
                if (attribute != null)
                {
                    if (attribute.Token == null)
                    {
                        GetInstance().Register(obj, item.Name, item);
                    }
                    else
                    {
                        GetInstance().Register(obj, attribute.Token, item);
                    }
                }
            }
        }
    }

    /// <summary>
    /// 注册
    /// </summary>
    /// <param name="obj"></param>
    public void RegistObject(object obj)
    {
        MethodInfo[] methods = obj.GetType().GetMethods();
        foreach (var item in methods)
        {
            RegistMethodAttribute attribute = item.GetCustomAttribute<RegistMethodAttribute>();
            if (attribute != null)
            {
                if (attribute.Token == null)
                {
                    GetInstance().Register(obj, item.Name, item);
                }
                else
                {
                    GetInstance().Register(obj, attribute.Token, item);
                }
            }
        }
    }

    private Dictionary<string, TokenInstance> tokenAndInstance { get; set; } = new Dictionary<string, TokenInstance>();

    /// <summary>
    /// 获取已注册的Token
    /// </summary>
    /// <returns></returns>
    public List<string> GetRegisterTokens()
    {
        List<string> cur = new List<string>();
        foreach (var item in tokenAndInstance)
        {
            cur.Add(item.Key);
        }

        return cur;
    }

    /// <summary>
    /// 注册消息
    /// </summary>
    /// <param name="register"></param>
    /// <param name="token"></param>
    /// <param name="action"></param>
    /// <exception cref="MessageRegisteredException"></exception>
    public void Register(object register, string token, Action action)
    {
        TokenInstance tokenInstance = new TokenInstance();
        tokenInstance.Register = register;
        tokenInstance.MethodInfo = action.Method;
        tokenInstance.ParameterTypes = Array.Empty<Type>();
        try
        {
            tokenAndInstance.Add(token, tokenInstance);
        }
        catch (Exception)
        {
            throw new MessageRegisteredException("该Token消息已注册");
        }
    }

    /// <summary>
    /// 注册消息
    /// </summary>
    /// <param name="register"></param>
    /// <param name="token"></param>
    /// <param name="methodInfo"></param>
    /// <exception cref="MessageRegisteredException"></exception>
    public void Register(object register, string token, MethodInfo methodInfo)
    {
        TokenInstance tokenInstance = new TokenInstance();
        tokenInstance.Register = register;
        tokenInstance.MethodInfo = methodInfo;

        // 初始化 ParameterTypes
        var parameters = methodInfo.GetParameters();
        tokenInstance.ParameterTypes = parameters.Select(p => p.ParameterType).ToArray();

        try
        {
            tokenAndInstance.Add(token, tokenInstance);
        }
        catch (Exception)
        {
            throw new MessageRegisteredException("该Token消息已注册");
        }
    }

    /// <summary>
    /// 注册消息
    /// </summary>
    /// <typeparam name="T">参数类型</typeparam>
    /// <param name="register"></param>
    /// <param name="token"></param>
    /// <param name="action"></param>
    /// <exception cref="MessageRegisteredException"></exception>
    public void Register<T>(object register, string token, Action<T> action)
    {
        TokenInstance tokenInstance = new TokenInstance();
        tokenInstance.Register = register;
        tokenInstance.MethodInfo = action.Method;
        try
        {
            tokenAndInstance.Add(token, tokenInstance);
        }
        catch (Exception)
        {
            throw new MessageRegisteredException("该Token消息已注册");
        }
    }

    /// <summary>
    /// 注册
    /// </summary>
    /// <typeparam name="T">参数类型</typeparam>
    /// <typeparam name="TReturn">返回值类型</typeparam>
    /// <param name="register"></param>
    /// <param name="token"></param>
    /// <param name="action"></param>
    public void Register<T, TReturn>(object register, string token, Func<T, TReturn> action)
    {
        TokenInstance tokenInstance = new TokenInstance();
        tokenInstance.Register = register;
        tokenInstance.MethodInfo = action.Method;
        try
        {
            tokenAndInstance.Add(token, tokenInstance);
        }
        catch (Exception)
        {
            throw new MessageRegisteredException("该Token消息已注册");
        }
    }

    /// <summary>
    /// 注册
    /// </summary>
    /// <typeparam name="T">参数类型</typeparam>
    /// <typeparam name="TParams">传参类型</typeparam>
    /// <typeparam name="TRetuen">返回值类型</typeparam>
    /// <param name="register"></param>
    /// <param name="token"></param>
    /// <param name="action"></param>
    public void Register<T, TParams, TRetuen>(object register, string token, Func<T, TParams, TRetuen> action)
    {
        TokenInstance tokenInstance = new TokenInstance();
        tokenInstance.Register = register;
        tokenInstance.MethodInfo = action.Method;
        try
        {
            tokenAndInstance.Add(token, tokenInstance);
        }
        catch (Exception)
        {
            throw new MessageRegisteredException("该Token消息已注册");
        }
    }

    /// <summary>
    /// 注册
    /// </summary>
    /// <typeparam name="TReturn">返回值类型</typeparam>
    /// <param name="register"></param>
    /// <param name="token"></param>
    /// <param name="action"></param>
    public void Register<TReturn>(object register, string token, Func<TReturn> action)
    {
        TokenInstance tokenInstance = new TokenInstance();
        tokenInstance.Register = register;
        tokenInstance.MethodInfo = action.Method;
        try
        {
            tokenAndInstance.Add(token, tokenInstance);
        }
        catch (Exception)
        {
            throw new MessageRegisteredException("该Token消息已注册");
        }
    }

    /// <summary>
    /// 通用的 Register 方法，支持任意参数数量
    /// </summary>
    /// <param name="register"></param>
    /// <param name="token"></param>
    /// <param name="methodInfo"></param>
    /// <param name="parameterTypes"></param>
    /// <exception cref="MessageRegisteredException"></exception>
    private void Register(object register, string token, MethodInfo methodInfo, params Type[] parameterTypes)
    {
        TokenInstance tokenInstance = new TokenInstance
        {
            Register = register,
            MethodInfo = methodInfo,
            ParameterTypes = parameterTypes
        };

        try
        {
            tokenAndInstance.Add(token, tokenInstance);
        }
        catch (Exception)
        {
            throw new MessageRegisteredException("该Token消息已注册");
        }
    }

    /// <summary>
    /// 通用的 Register 方法，支持任意参数数量
    /// </summary>
    /// <param name="register"></param>
    /// <param name="token"></param>
    /// <param name="handler"></param>
    public void Register(object register, string token, Delegate handler)
    {
        MethodInfo method = handler.Method;
        Type[] paramTypes = method.GetParameters().Select(p => p.ParameterType).ToArray();

        Register(register, token, method, paramTypes);
    }

    /// <summary>
    /// 卸载消息
    /// </summary>
    /// <param name="register"></param>
    public void Unregister(object register)
    {
        List<string> key = new List<string>();

        foreach (var item in tokenAndInstance.Keys)
        {
            if (register == tokenAndInstance[item].Register)
            {
                key.Add(item);
            }
        }

        foreach (var item in key)
        {
            tokenAndInstance.Remove(item);
        }
    }

    /// <summary>
    /// 发送消息
    /// </summary>
    /// <param name="token"></param>
    /// <param name="parameters"></param>
    /// <exception cref="MessageNotFoundException"></exception>
    public void Send(string token, params object[] parameters)
    {
        if(parameters==null)
            throw new ArgumentException("参数如果没有也不要传null");

        #region 20250521 注释
        //if (tokenAndInstance.TryGetValue(token, out var Method))
        //{
        //    var attributes = Method.MethodInfo.GetCustomAttributes<MessengerAopBaseAttribute>(true);
        //    var context = new MessengerAopContext()
        //    {
        //        MethodName = $"{Method.MethodInfo.ReflectedType.FullName}.{Method.MethodInfo.Name}",
        //        MessengerToken = token,
        //        PassData = parameters,
        //        ExcutingTime = DateTime.Now,
        //    };

        //    foreach (var attribute in attributes)
        //    {
        //        attribute.ExcuteBefore(context);
        //    }

        //    try
        //    {
        //        context.MethodResult = Method.MethodInfo.Invoke(Method.Register, parameters);
        //        context.ExcutedTime = DateTime.Now;
        //    }
        //    catch (Exception ex)
        //    {
        //        context.ExceptionInfo = ex;
        //    }

        //    foreach (var attribute in attributes)
        //    {
        //        attribute.ExcuteAfter(context);
        //    }
        //}
        //else
        //{
        //    throw new MessageNotFoundException("未找到该消息");
        //} 
        #endregion

        if (tokenAndInstance.TryGetValue(token, out var tokenInstance))
        {
            if(tokenInstance.ParameterTypes==null)
                tokenInstance.ParameterTypes = new Type[0];

            // 参数数量检查
            if (parameters.Length != tokenInstance.ParameterTypes.Length)
            {
                throw new ArgumentException("参数数量不匹配");
            }

            // 参数类型检查
            for (int i = 0; i < parameters.Length; i++)
            {
                if (parameters[i] != null && !tokenInstance.ParameterTypes[i].IsAssignableFrom(parameters[i].GetType()))
                {
                    throw new ArgumentException($"参数{i}类型不匹配，期望类型：{tokenInstance.ParameterTypes[i]}, 实际类型：{parameters[i].GetType()}");
                }
            }

            var context = new MessengerAopContext
            {
                MethodName = $"{tokenInstance.MethodInfo.ReflectedType.FullName}.{tokenInstance.MethodInfo.Name}",
                MessengerToken = token,
                PassData = parameters,
                ExcutingTime = DateTime.Now,
            };

            var attributes = tokenInstance.MethodInfo.GetCustomAttributes<MessengerAopBaseAttribute>(true);
            foreach (var attribute in attributes)
            {
                attribute.ExcuteBefore(context);
            }

            try
            {
                context.MethodResult = tokenInstance.MethodInfo.Invoke(tokenInstance.Register, parameters);
                context.ExcutedTime = DateTime.Now;
            }
            catch (Exception ex)
            {
                context.ExceptionInfo = ex;
            }

            foreach (var attribute in attributes)
            {
                attribute.ExcuteAfter(context);
            }
        }
        else
        {
            throw new MessageNotFoundException("未找到该消息");
        }
    }

    /// <summary>
    /// 发送消息
    /// </summary>
    /// <typeparam name="T">返回值类型</typeparam>
    /// <param name="token"></param>
    /// <param name="parameters"></param>
    /// <returns></returns>
    /// <exception cref="MessageNotFoundException"></exception>
    public T Send<T>(string token, params object[] parameters)
    {
        #region 20250521 注释
        //if (tokenAndInstance.TryGetValue(token, out var Method))
        //{
        //    var attributes = Method.MethodInfo.GetCustomAttributes<MessengerAopBaseAttribute>(true);
        //    var context = new MessengerAopContext()
        //    {
        //        MethodName = $"{Method.MethodInfo.ReflectedType.FullName}.{Method.MethodInfo.Name}",
        //        MessengerToken = token,
        //        PassData = parameters,
        //        ExcutingTime = DateTime.Now,
        //    };

        //    foreach (var attribute in attributes)
        //    {
        //        attribute.ExcuteBefore(context);
        //    }

        //    try
        //    {
        //        context.MethodResult = Method.MethodInfo.Invoke(Method.Register, parameters);
        //        context.ExcutedTime = DateTime.Now;
        //    }
        //    catch (Exception ex)
        //    {
        //        context.ExceptionInfo = ex;
        //    }

        //    foreach (var attribute in attributes)
        //    {
        //        attribute.ExcuteAfter(context);
        //    }

        //    return (T)context.MethodResult;
        //}
        //else
        //{
        //    throw new MessageNotFoundException("未找到该消息");
        //} 
        #endregion

        if (tokenAndInstance.TryGetValue(token, out var tokenInstance))
        {
            // 参数数量检查
            if (parameters.Length != tokenInstance.ParameterTypes.Length)
            {
                throw new ArgumentException("参数数量不匹配");
            }

            // 参数类型检查
            for (int i = 0; i < parameters.Length; i++)
            {
                if (parameters[i] != null && !tokenInstance.ParameterTypes[i].IsAssignableFrom(parameters[i].GetType()))
                {
                    throw new ArgumentException($"参数{i}类型不匹配，期望类型：{tokenInstance.ParameterTypes[i]}, 实际类型：{parameters[i].GetType()}");
                }
            }

            var context = new MessengerAopContext
            {
                MethodName = $"{tokenInstance.MethodInfo.ReflectedType.FullName}.{tokenInstance.MethodInfo.Name}",
                MessengerToken = token,
                PassData = parameters,
                ExcutingTime = DateTime.Now,
            };

            var attributes = tokenInstance.MethodInfo.GetCustomAttributes<MessengerAopBaseAttribute>(true);
            foreach (var attribute in attributes)
            {
                attribute.ExcuteBefore(context);
            }

            try
            {
                context.MethodResult = tokenInstance.MethodInfo.Invoke(tokenInstance.Register, parameters);
                context.ExcutedTime = DateTime.Now;
            }
            catch (Exception ex)
            {
                context.ExceptionInfo = ex;
            }

            foreach (var attribute in attributes)
            {
                attribute.ExcuteAfter(context);
            }

            return (T)context.MethodResult;
        }
        else
        {
            throw new MessageNotFoundException("未找到该消息");
        }
    }
}

/// <summary>
///  
/// </summary>
internal class TokenInstance
{
    public object Register { get; set; }
    public MethodInfo MethodInfo { get; set; }

    public Type[] ParameterTypes { get; set; } = Array.Empty<Type>();
}